#pragma once
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/net/Buffer.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/TcpClient.h>
#include "Detail/fields.hpp"
#include "Detail/json.hpp"
#include "Detail/log.hpp"
#include "Detail/uuid.hpp"
#include "abstracr.hpp"
#include "message.hpp"

namespace rpc
{
    class MuduoBuffer : public BaseBuffer
    {
    public:
        using ptr = std::shared_ptr<MuduoBuffer>;
        MuduoBuffer(muduo::net::Buffer *buf) : _buf(buf) {}
        virtual size_t readableSize() override
        {
            return _buf->readableBytes();
        }
        virtual int32_t peekInit32() override
        {
            return _buf->peekInt32();
        }
        virtual void retrieveInt32() override
        {
            return _buf->retrieveInt32();
        }
        virtual int32_t readInit32() override
        {
            return _buf->readInt32();
        }
        virtual std::string retrieveAsString(size_t len) override
        {
            return _buf->retrieveAsString(len);
        }

    private:
        muduo::net::Buffer *_buf;
    };

    class BufferFactory
    {
    public:
        template <typename... Args>
        static BaseBuffer::ptr create(Args &&...args)
        {
            return std::make_shared<MuduoBuffer>(std::forward(args)...);
        }
    };

    class LVProtocol : public BaseProtocol
    {
    public:
        using ptr = std::shared_ptr<LVProtocol>;
        // 判断缓冲区中的数据量是否足够一条消息的处理
        virtual bool canProcessed(const BaseBuffer::ptr &buf) override
        {
            //|--len--|--value--|
            //|--len--|--mtype--idlen--id--body--|

            // 取出len（总长度）
            int32_t total_len = buf->peekInit32();
            // 判断够不够一条消息
            if (buf->readableSize() < (total_len + lenFieldsLength))
                return false;
            return true;
        }

        virtual bool onMessage(const BaseBuffer::ptr &buf, BaseMessage::ptr &msg) override
        {
            // 当调用该函数的时候，默认认为缓冲区的数据足够一条完整的消息
            int32_t total_len = buf->readInit32();  // 读取总长度
            MType mtype = (MType)buf->readInit32(); // 读取类型长度
            int32_t idlen = buf->readInit32();      // 读取id长度

            int32_t body_len = total_len - idlen - idlenFieldsLength - mtypeFieldsLength;
            std::string id = buf->retrieveAsString(idlen);
            std::string body = buf->retrieveAsString(body_len);

            auto msg = MessageFactory::create(mtype);
            if (msg.get() == nullptr)
            {
                ERR("消息类型错误，构造消息对象失败");
                return false;
            }
            bool ret = msg->unserialize(body);
            if (ret == false)
            {
                ERR("消息正文反序列化失败");
                return false;
            }

            msg->setId(id);
            msg->setMType(mtype);
            return true;
        }
        virtual std::string serialize(const BaseMessage::ptr &msg) override
        {
            std::string body = msg->serialize();
            std::string id = msg->rid();

            MType mtype = (MType)htonl((int32_t)msg->mtype());
            int32_t idlen = htonl(id.size());
            int32_t total_len = htonl(mtypeFieldsLength + idlenFieldsLength + idlen + body.size());

            std::string result;
            result.reserve(total_len);
            result.append((char *)&total_len, lenFieldsLength);
            result.append((char *)&mtype, mtypeFieldsLength);
            result.append((char *)&idlen, idlenFieldsLength);
            result.append(id);
            result.append(body);
        }

    private:
        const size_t lenFieldsLength = 4;   // len字段的长度
        const size_t mtypeFieldsLength = 4; // mtype消息类型字段长度
        const size_t idlenFieldsLength = 4; // id字段长度
    };

    class ProtocolFactory
    {
    public:
        template <typename... Args>
        static BaseProtocol::ptr create(Args &&...agrs)
        {
            return std::make_shared<LVProtocol>(std::forward(args)...);
        }
    };

    class MuduoConnection : public BaseConnection
    {
    public:
        using ptr = std::shared_ptr<MuduoConnection>;
        MuduoConnection(const BaseProtocol::ptr &protocol, muduo::net::TcpConnectionPtr &conn)
        :_protocol(protocol), _conn(conn)
        {}

        virtual void send(const BaseMessage::ptr &msg) override
        {
            std::string body = _protocol->serialize(msg);
            _conn->send(body);
        }
        virtual void shutdown() override
        {
            _conn->shutdown();
        }
        virtual bool connected() override
        {
            _conn->connected();
        }
    private:
        BaseProtocol::ptr _protocol;
        muduo::net::TcpConnectionPtr _conn;
    };

    class ConnectionFactory
    {
    public:
        template <typename... Args>
        static BaseConnection::ptr create(Args &&...agrs)
        {
            return std::make_shared<MuduoConnection>(std::forward(args)...);
        }
    };

    class MuduoServer : public BaseServer
    {
    public:
        using ptr = std::shared_ptr<MuduoServer>;
        MuduoServer
        virtual void Start() = 0;
    };
}
